package org.dreamwork.jasmine2.javac;

import org.dreamwork.jasmine2.web.controls.Page;

import java.io.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by IntelliJ IDEA.
 * User: seth
 * Date: 2009-2-2
 * Time: 15:38:42
 */
public class JasmineClassLoader {
    private File dir;
//    private ClassLoader loader;
    private static final Map<String, Long> map = new ConcurrentHashMap<> ();
    private static final Map<String, ClassLoader> loaders = new ConcurrentHashMap<> ();

    public JasmineClassLoader (File outdir) {
        dir = outdir;
    }

    public Page load (String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        boolean resolve = className.startsWith ("jasmine.autogen");
        Class clazz;
        if (resolve) {
            clazz = loadGeneratedClass (className);
        } else
            clazz = Thread.currentThread ().getContextClassLoader ().loadClass (className);

        if (clazz != null) {
            if (Page.class.isAssignableFrom (clazz))
                return (Page) clazz.newInstance ();
            throw new ClassCastException (className);
        }

        throw new ClassNotFoundException (className);
    }

    private Class loadGeneratedClass (String className) throws ClassNotFoundException {
        ClassLoader loader = loaders.get (className);
        boolean modified = false;
        String path = className.replace ('.', '/');
        File file =  new File (dir, path + ".class");
        if (loader != null) {
            long lastModify = map.get (className);
            modified = lastModify < file.lastModified ();
        }

        if (loader == null || modified) {
            try {
                loader = new URLClassLoader (new URL[] {dir.toURI ().toURL ()}, Thread.currentThread ().getContextClassLoader ());
                synchronized (loaders) {
                    loaders.put (className, loader);
                }
            } catch (Exception ex) {
                throw new ClassNotFoundException (className);
            }
        }
        Class c = loader.loadClass (className);
        map.put (className, file.lastModified ());
        return c;
    }

    public void removeLoader (String className) {
        synchronized (loaders) {
            if (loaders.containsKey (className))
                loaders.remove (className);
        }
    }
}